package com.shadow.demo.dictionary.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.shadow.demo.dictionary.common.CollectionUtil;
import com.shadow.demo.dictionary.common.ParseUtil;
import com.shadow.demo.dictionary.dto.DicDTO;
import com.shadow.demo.dictionary.dto.DicItemDTO;
import com.shadow.demo.dictionary.entity.DicEntity;
import com.shadow.demo.dictionary.entity.DicItemEntity;
import com.shadow.demo.dictionary.enums.DicEnum;
import com.shadow.demo.dictionary.mapper.DicItemMapper;
import com.shadow.demo.dictionary.mapper.DicMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class DicItemService extends BaseService<DicItemMapper, DicItemEntity> implements IService<DicItemEntity> {

    private final DicItemMapper dicItemMapper;
    private final DicCacheService dicCacheService;
    private final DicMapper dicMapper;

    DicItemService(DicItemMapper dicItemMapper, DicCacheService dicCacheService, DicMapper dicMapper) {
        this.dicItemMapper = dicItemMapper;
        this.dicCacheService = dicCacheService;
        this.dicMapper = dicMapper;
    }
    
    public void removeDicByIds(String... dicIds) {
        if (dicIds != null && dicIds.length > 0) {
            removeDicItemByDicIds(Arrays.asList(dicIds));
            for (String dicId : dicIds) {
                dicCacheService.removeDicCacheById(dicId);
            }
        }
    }

//    public QueryResult<DicEntity> searchDic(QueryFilter filter) {
//        return JpaQuery.select(em, QDic).from(QDic).where(filter, QDic.name, QDic.groupPath, QDic.desc).page(filter)
//                .orderBy(QDic.sortNo.desc().nullsLast()).toQueryResult();
//    }
    
    public List<DicItemEntity> listSubDicItemByName(final String dicName, String parentId) {
        if (StringUtils.isEmpty(parentId)) {
            parentId = DicEnum.RootId;
        }
        LambdaQueryWrapper<DicEntity> queryWrapper = new LambdaQueryWrapper<DicEntity>()
                .eq(DicEntity::getName, dicName);
        List<DicEntity> dicEntityList = dicMapper.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(dicEntityList)) {
            return Collections.emptyList();
        }
        LambdaQueryWrapper<DicItemEntity> queryWrapper1 = new LambdaQueryWrapper<DicItemEntity>()
                .in(DicItemEntity::getDicId, dicEntityList.stream().map(DicEntity::getId).collect(Collectors.toList()))
                .eq(DicItemEntity::getParentId, parentId)
                .eq(DicItemEntity::getName, dicName)
                .orderByAsc(DicItemEntity::getSortNo);
        return dicItemMapper.selectList(queryWrapper1);
    }



    /**
     * 取得字典项及其子项的所有Id
     *
     * @param dicItemIds 字典项的Id
     * @return
     */
    private List<String> listDicItemIdWithSubTree(List<String> dicItemIds) {
        List<String> allIds = new ArrayList<>();
        List<String> parentIds = dicItemIds;
        LambdaQueryWrapper<DicItemEntity> wrapper = new LambdaQueryWrapper<DicItemEntity>()
                .select(DicItemEntity::getId)
                .in(DicItemEntity::getParentId, dicItemIds);
        List<String> temp = dicItemMapper.selectList(wrapper)
                .stream()
                .map(DicItemEntity::getId)
                .collect(Collectors.toList());
        for (String parentId : parentIds) {
//
//            List<String> temp = JpaQuery.select(em, QDicItem.id)
//                    .from(QDicItem)
//                    .where(QDicItem.parentId.in(dicItemIds))
//                    .toList();
            allIds.addAll(parentIds);
            parentIds.clear();
            for (String id : temp) {
                if (!allIds.contains(id)) {
                    parentIds.add(id);
                }
            }
        }
        return allIds;
    }

    public List<DicItemEntity> listDicItemByName(String dicName, List<String> dicItemNameList) {
        if (CollectionUtils.isNotEmpty(dicItemNameList)) {
            List<DicEntity> dicEntityList = dicMapper.selectList(
                    new LambdaQueryWrapper<DicEntity>().eq(DicEntity::getName, dicName)
            );
            if (CollectionUtils.isNotEmpty(dicEntityList)) {
                LambdaQueryWrapper<DicItemEntity> queryWrapper1 = new LambdaQueryWrapper<DicItemEntity>()
                        .in(DicItemEntity::getDicId, dicEntityList.stream().map(DicEntity::getId).collect(Collectors.toList()))
                        .in(DicItemEntity::getName, dicItemNameList);
                return dicItemMapper.selectList(queryWrapper1);
            }
        }
        return Collections.emptyList();
    }
    
//    public HashMap<String, DicItemEntity> setDicItem(HashMap<Integer, List<DicItemDTO>> dicItemDtoMap, HashMap<String, DicItemEntity> dicItemEntity) {
//        HashMap<Integer, List<DicItemDTO>> childrenItem = new HashMap<>();
//        for (Map.Entry<Integer, List<DicItemDTO>> entry : dicItemDtoMap.entrySet()) {
//            List<DicItemDTO> dicItem = entry.getValue();
//            for (int i = 0; i < dicItem.size(); i++) {
//                DicItemDTO dicItemDTO = dicItem.get(i);
//                dicItemEntity.put(dicItemDTO.getId(), ParseUtil.parseValue(DicItemEntity.class, dicItemDTO));
//                if (dicItemDTO.getChildren() != null && dicItemDTO.getChildren().size() > 0) {
//                    childrenItem.put(i, dicItemDTO.getChildren());
//                    setDicItem(childrenItem, dicItemEntity);
//                }
//            }
//        }
//        return dicItemEntity;
//    }
//    public void saveDicItemByLevel(HashMap<String, DicItemEntity> allDicItem, String newKey, String oldKey) {
//        allDicItem.forEach((index, value) -> {
//            String parentId = value.getParentId();
//            String itemOldId = value.getId();
//            if (Objects.equals(parentId, oldKey)) {
//                value.setParentId(newKey);
//                DicItemEntity dicItemTop = saveDicItem(value);
//                String topId = dicItemTop.getId();
//                saveDicItemByLevel(allDicItem, topId, itemOldId);
//            }
//        });
//    }
//    public List<String> importDicFiles(MultipartFile file) {
//        InputStream inputStream = null;
//        // 存放消息
//        List<String> msgList = new ArrayList<>();
//        Integer sortNo = getMaxDicSortNo();
//        try {
//            inputStream = file.getInputStream();
//            String dicStr = IoUtil.readText(inputStream, StandardCharsets.UTF_8.name());
//            List<DicDTO> dicList = JSON.parseArray(dicStr, DicDTO.class);
//            if (dicList == null) {
//                throw new RuntimeException();
//            }
//            for (int i = 0; i < dicList.size(); i++) {
//                // 检测字典名称是否存在
//                DicDTO dicItem = dicList.get(i);
//                String itemName = dicItem.getName();
//                DicEntity dicByName = getDicByName(itemName);
//
//                if (dicByName != null) {
//                    dicItem.setModifyTime(DateUtil.getSysTime());
//                    if (dicItem.getSortNo() == null) {
//                        dicItem.setSortNo(getMaxDicSortNo());
//                        sortNo++;
//                    }
//                    dicByName = em.merge(ParseUtil.parseValue(DicEntity.class, dicItem));
//                    String dicNewId = dicByName.getId();
//                    List<DicItemDTO> childList = dicItem.getItems();
//                    saveDicItem(dicNewId, childList, "/");
//                } else {
//                    dicItem.setId("");
//                    if (dicItem.getSortNo() == null) {
//                        dicItem.setSortNo(getMaxDicSortNo());
//                        sortNo++;
//                    }
//                    dicItem.setModifyTime(DateUtil.getSysTime());
//                    dicByName = em.merge(ParseUtil.parseValue(DicEntity.class, dicItem));
//                    String dicNewId = dicByName.getId();
//                    List<DicItemDTO> childList = dicItem.getItems();
//                    saveDicItem(dicNewId, childList, "/");
//                }
//            }
//        } catch (IOException ex) {
//            LogUtil.error(this, ex);
//            throw new RuntimeException();
//        } finally {
//            IoUtil.closeQuietly(inputStream);
//        }
//        return msgList;
//    }
//    public List<DicItemDTO> parseDicFile(MultipartFile file) {
//        String ext = PathUtil.getFileExt(file.getOriginalFilename());
//        InputStream inputStream = null;
//        List<DicItemDTO> list = new ArrayList<>();
//        try {
//            if (".json".equalsIgnoreCase(ext)) {
//                inputStream = file.getInputStream();
//                String dicStr = IoUtil.readText(inputStream, StandardCharsets.UTF_8.name());
//                list = JSON.parseArray(dicStr, DicItemDTO.class);
//            } else if (".xlsx".equalsIgnoreCase(ext) || ".xls".equalsIgnoreCase(ext)) {
//                List<Map<String, Object>> excelDataList = ExcelUtil.getExcelData(file);
//                String js = JSON.toJSONString(excelDataList);
//                list = JSON.parseArray(js, DicItemDTO.class);
//            }
//        } catch (Exception ex) {
//            log.error(ex.getMessage());
//        } finally {
//            IoUtil.closeQuietly(inputStream);
//        }
//
//        return list;
//    }
//    public List<DicDTO> parseDicFileNew(MultipartFile file) {
//        InputStream inputStream = null;
//        try {
//            inputStream = file.getInputStream();
//            String dicStr = IoUtil.readText(inputStream, StandardCharsets.UTF_8.name());
//            List<DicDTO> dicList = JSON.parseArray(dicStr, DicDTO.class);
//            return dicList;
//        } catch (Exception ex) {
//            LogUtil.error(ex.getMessage());
//        } finally {
//            IoUtil.closeQuietly(inputStream);
//        }
//        return Collections.EMPTY_LIST;
//    }
    
    @Transactional
    @CacheEvict(value = "dicItemByDicId", allEntries = true)
    public void importDicFilesNew(List<DicDTO> dicDTOList) {
        if (CollectionUtils.isEmpty(dicDTOList)) {
            return;
        }
        List<String> dicNameList = dicDTOList.stream()
                .map(DicDTO::getName)
                .collect(Collectors.toList());
        LambdaQueryWrapper<DicEntity> wrapper = new LambdaQueryWrapper<DicEntity>()
                .in(DicEntity::getName, dicNameList);

        // 数据库存在, 需要更新的
        List<DicEntity> existDicList = dicMapper.selectList(wrapper);
        // 数据库不存在, 需要新增的
        List<DicDTO> notexistDiclist = dicDTOList.stream()
                .filter(item -> !existDicList.stream()
                        .map(DicEntity::getName)
                        .collect(Collectors.toList())
                        .contains(item.getName()))
                .collect(Collectors.toList());

        /*
         *  对于差异的直接新增
         */
        Integer sortNo = getMaxDicSortNo();
        for (DicDTO dicDTO : notexistDiclist) {
            DicEntity dicEntity = ParseUtil.parseValue(DicEntity.class, dicDTO);
            dicEntity.setModifyTime(Calendar.getInstance().getTime());
            dicEntity.setSortNo(sortNo);
            dicMapper.insert(dicEntity);
            sortNo++;
            List<DicItemDTO> childList = dicDTO.getItems();
            saveDicItem(dicEntity.getId(), childList, "/");
        }
        /*
         *  对于已存在的做更新
         */
        for (DicEntity dicEntity : existDicList) {
            DicDTO dicDTO = compareWithDicList(dicEntity.getName(), dicDTOList);
            if (dicDTO == null) {
                continue;
            }
            updateDicAndDicItem(dicDTO);
        }
    }

    public DicDTO compareWithDicList(String dicName, List<DicDTO> dicDTOList) {
        for (DicDTO dicDTO : dicDTOList) {
            if (dicName.equals(dicDTO.getName())) {
                return dicDTO;
            }
        }
        return null;
    }

    @Transactional
    public DicDTO updateDicAndDicItem(DicDTO dicDTO) {
        DicEntity dicUpt = ParseUtil.parseValue(DicEntity.class, dicDTO);
        dicUpt.setModifyTime(Calendar.getInstance().getTime());
        if (dicUpt.getSortNo() == null) {
            dicUpt.setSortNo(getMaxDicSortNo());
        }
        dicMapper.updateById(dicUpt);
        List<DicItemEntity> existDicList = listDicItemByDicIds(Collections.singletonList(dicDTO.getId()));
        List<DicItemDTO> dicItemTreeList = dicDTO.getItems();
        List<DicItemDTO> simpleList = new ArrayList<>();
        flattens(dicItemTreeList, simpleList);

        List<DicItemEntity> diffBizFromList = existDicList.stream()
                .filter(item -> !simpleList.stream()
                        .map(DicItemDTO::getId)
                        .collect(Collectors.toList())
                        .contains(item.getId()))
                .collect(Collectors.toList());

        //删除记录
        List<String> itemIds = diffBizFromList.stream().map(DicItemEntity::getId).collect(Collectors.toList());
        removeDicItemByIds(itemIds);
        for (DicItemDTO dicItemDTO : simpleList) {
            saveDicItem(ParseUtil.parseValue(DicItemEntity.class, dicItemDTO));
        }
        return dicDTO;
    }

    public void removeDicItemByIds(List<String> dicItemIdList) {
        if (CollectionUtils.isNotEmpty(dicItemIdList)) {
            List<String> ids = listDicItemIdWithSubTree(dicItemIdList);
            LambdaQueryWrapper<DicItemEntity> wrapper = new LambdaQueryWrapper<DicItemEntity>()
                    .in(DicItemEntity::getId, ids);
            dicItemMapper.delete(wrapper);
        }
    }

    public void flattens(List<DicItemDTO> flatList, List<DicItemDTO> simpleList) {
        for (DicItemDTO dicItem : flatList) {
            if (!CollectionUtils.isEmpty(dicItem.getChildren())) {
                List<DicItemDTO> children = dicItem.getChildren() == null ? new ArrayList<>() : dicItem.getChildren();
                dicItem.setChildren(new ArrayList<>());
                simpleList.add(dicItem);
                flattens(children, simpleList);
            } else {
                simpleList.add(dicItem);
            }
        }
    }
    
    @CacheEvict(value = "dicItemByDicId", key = "#dicId")
    public Boolean importDicFileByDicId(String dicId, List<DicItemDTO> itemlist) {
        List<DicItemDTO> dataNode = new ArrayList<>();
        fillList(dataNode, itemlist);
        List<DicItemEntity> list = treeNode2EntityList(dicId, dataNode);
        Integer sortNo = getMaxDicItemSortNo(dicId);
        for (DicItemEntity dicItem : list) {
            if (dicItem.getSortNo() == null) {
                dicItem.setSortNo(sortNo);
                sortNo++;
            }
            if (StringUtils.isEmpty(dicItem.getId())) {
                dicItemMapper.insert(dicItem);
            } else {
                dicItemMapper.updateById(dicItem);
            }
        }
        return Boolean.TRUE;
    }

    public void fillList(List<DicItemDTO> dataNode, List<DicItemDTO> list) {
        for (DicItemDTO dicTreeNode : list) {
            dataNode.add(dicTreeNode);
            if (CollectionUtils.isNotEmpty(dicTreeNode.getChildren())) {
                fillList(dataNode, dicTreeNode.getChildren());
            }
        }
    }

    public List<String> getDicIdByDicItemIds(final List<String> idList) {
        if (CollectionUtils.isNotEmpty(idList)) {
            LambdaQueryWrapper<DicItemEntity> wrapper = new LambdaQueryWrapper<DicItemEntity>()
                    .select(DicItemEntity::getDicId)
                    .in(DicItemEntity::getId, idList);
            return dicItemMapper.selectList(wrapper)
                    .stream()
                    .map(DicItemEntity::getDicId)
                    .distinct()
                    .collect(Collectors.toList());
        }
        return Collections.emptyList();
    }

    /**
     * 通过id查询字典项
     * @param dicIdList 字典id
     * */
    public List<DicItemEntity> getDicItemByIds(final List<String> dicIdList) {
        if (CollectionUtils.isNotEmpty(dicIdList)) {
            LambdaQueryWrapper<DicItemEntity> wrapper = new LambdaQueryWrapper<DicItemEntity>()
                    .in(DicItemEntity::getDicId, dicIdList);
            return dicItemMapper.selectList(wrapper);
        }
        return Collections.emptyList();
    }

    /**
     * 通过id查询字典项2
     * @param dicIdList 字典id
     * */
    @Cacheable(cacheNames = "dicItemByDicId", key = "#dicIdList")
    public List<DicItemEntity> listDicItemByDicIds(List<String> dicIdList) {
        if (CollectionUtils.isNotEmpty(dicIdList)) {
            LambdaQueryWrapper<DicItemEntity> wrapper = new LambdaQueryWrapper<DicItemEntity>()
                    .in(DicItemEntity::getDicId, dicIdList)
                    .orderByAsc(DicItemEntity::getSortNo);
            return dicItemMapper.selectList(wrapper);
        }
        return Collections.emptyList();
    }

    /**
     * 通过名称查询字典项
     * */
    public DicItemEntity getDicItemByName(String dicId, String name, String parentId) {
        LambdaQueryWrapper<DicItemEntity> wrapper = new LambdaQueryWrapper<DicItemEntity>()
                .eq(DicItemEntity::getDicId, dicId)
                .eq(DicItemEntity::getName, name)
                .eq(DicItemEntity::getParentId, parentId == null ? DicEnum.RootId : parentId)
                .last("limit 1");
        return dicItemMapper.selectOne(wrapper);
    }

    /**
     * 获取特定字典子项
     * @param dicId 字典id
     * @param parentId parentId
     * */
    public List<DicItemEntity> listSubDicItem(final String dicId, final String parentId) {
        LambdaQueryWrapper<DicItemEntity> wrapper = new LambdaQueryWrapper<DicItemEntity>()
                .eq(DicItemEntity::getDicId, dicId)
                .eq(DicItemEntity::getParentId, StringUtils.isEmpty(parentId) ? DicEnum.RootId : parentId)
                .orderByAsc(DicItemEntity::getSortNo);
        return dicItemMapper.selectList(wrapper);
    }

    /**
     * 获取特定字典子项
     * @param parentIdList 字典id
     * */
    public List<DicItemEntity> listSubDicItemByIds(final List<String> parentIdList) {
        if (CollectionUtils.isNotEmpty(parentIdList)) {
            LambdaQueryWrapper<DicItemEntity> wrapper = new LambdaQueryWrapper<DicItemEntity>()
                    .in(DicItemEntity::getParentId, parentIdList)
                    .orderByAsc(DicItemEntity::getSortNo);
            return dicItemMapper.selectList(wrapper);
        }
        return Collections.emptyList();
    }

    /**
     * 保存字典项
     * */
    @CacheEvict(value = "dicItemByDicId", key = "#dicItemEntity.dicId")
    public DicItemEntity saveDicItem(final DicItemEntity dicItemEntity) {
        dicItemMapper.insert(dicItemEntity);
        return dicItemEntity;
    }

    /**
     * 通过id删除字典项
     * */
    @CacheEvict(value = "dicItemByDicId", key = "#dicList")
    public void removeDicItemByDicIds(final List<String> dicList) {
        if (CollectionUtils.isNotEmpty(dicList)) {
            LambdaQueryWrapper<DicItemEntity> wrapper = new LambdaQueryWrapper<DicItemEntity>()
                    .in(DicItemEntity::getDicId, dicList);
            dicItemMapper.delete(wrapper);
        }
    }

    /**
     * 查询字典项最大排序
     * */
    public Integer getMaxDicItemSortNo(final String dicId) {
        Integer max = dicItemMapper.getMaxDicItemSortNo(dicId);
        log.info("查询字典项最大排序, max: {}", max);
        return max == null ? 1 : max + 1;
    }

    private void saveDicItem(String dicId, List<DicItemDTO> dicItemDTOList, String parentId) {
        if (CollectionUtils.isEmpty(dicItemDTOList)) {
            return;
        }
        dicItemDTOList.forEach(dicItemDTO -> {
            DicItemEntity dicItemEntity = ParseUtil.parseValue(DicItemEntity.class, dicItemDTO);
            dicItemEntity.setDicId(dicId);
            dicItemEntity.setId("");
            dicItemEntity.setParentId(parentId);
            dicItemMapper.insert(dicItemEntity);
            if (!CollectionUtil.isEmptys(dicItemDTO.getChildren())) {
                saveDicItem(dicId, dicItemDTO.getChildren(), dicItemEntity.getId());
            }
        });
    }

    public List<DicItemEntity> treeNode2EntityList(String dicId, List<DicItemDTO> poList) {
        List<DicItemEntity> list = new ArrayList<>();
        if (poList == null || poList.isEmpty())
            return list;
        for (DicItemDTO po : poList) {
            DicItemEntity dicItem = new DicItemEntity();
            if (!StringUtils.isEmpty(po.getId())) {
                dicItem.setId(po.getId());
            }
            dicItem.setName(po.getName());
            dicItem.setValue(po.getValue());
            dicItem.setDicId(dicId);
            dicItem.setParentId(po.getParentId());
            dicItem.setSortNo(po.getSortNo());
            list.add(dicItem);
        }
        return list;
    }

    /**
     * 查询字典最大排序
     * */
    public Integer getMaxDicSortNo() {
        Integer max = dicMapper.getMaxDicSortNo();
        log.info("查询字典最大排序, max: {}", max);
        return max == null ? 1 : max + 1;
    }
}
